package org.villacoapa.censo.web.registro;

import java.io.Reader;
import java.io.StringReader;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;
import org.apache.log4j.Logger;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.villacoapa.censo.HibernateSessionFactory;
import org.villacoapa.censo.dao.Bautizo;
import org.villacoapa.censo.dao.BautizoDAO;
import org.villacoapa.censo.dao.Cargo;
import org.villacoapa.censo.dao.CargoDAO;
import org.villacoapa.censo.dao.DelegacionDAO;
import org.villacoapa.censo.dao.DepartamentoDAO;
import org.villacoapa.censo.dao.EstadoCivilDAO;
import org.villacoapa.censo.dao.EstatusMiembroDAO;
import org.villacoapa.censo.dao.Familia;
import org.villacoapa.censo.dao.FamiliaDAO;
import org.villacoapa.censo.dao.Miembro;
import org.villacoapa.censo.dao.MiembroCargoActualDAO;
import org.villacoapa.censo.dao.MiembroCargoDeseado;
import org.villacoapa.censo.dao.MiembroCargoDeseadoDAO;
import org.villacoapa.censo.dao.MiembroCargoDeseadoId;
import org.villacoapa.censo.dao.MiembroCargoLlevado;
import org.villacoapa.censo.dao.MiembroCargoLlevadoDAO;
import org.villacoapa.censo.dao.MiembroDAO;
import org.villacoapa.censo.dao.MiembroSubarea;
import org.villacoapa.censo.dao.MiembroSubareaDAO;
import org.villacoapa.censo.dao.MiembroSubareaId;
import org.villacoapa.censo.dao.OcupacionDAO;
import org.villacoapa.censo.dao.OtraFeligrecia;
import org.villacoapa.censo.dao.OtraFeligreciaDAO;
import org.villacoapa.censo.dao.Padecimiento;
import org.villacoapa.censo.dao.PadecimientoDAO;
import org.villacoapa.censo.dao.PadecimientosMiembro;
import org.villacoapa.censo.dao.PadecimientosMiembroDAO;
import org.villacoapa.censo.dao.PadecimientosMiembroId;
import org.villacoapa.censo.dao.PosicionCargoDAO;
import org.villacoapa.censo.dao.Subarea;
import org.villacoapa.censo.dao.SubareaDAO;
import org.villacoapa.censo.dao.TemaInteres;
import org.villacoapa.censo.dao.TemaInteresDAO;
import org.villacoapa.censo.dao.TemaInteresMiembro;
import org.villacoapa.censo.dao.TemaInteresMiembroDAO;
import org.villacoapa.censo.dao.TemaInteresMiembroId;
import org.villacoapa.censo.web.exception.FotoRegistradaException;
import org.villacoapa.censo.web.xml.parser.Parser;

public class Registro {
	
	private static Logger log = Logger.getLogger(Registro.class);
	
	private Element root;
	private String xml;
	private FamiliaDAO familiaDAO = null;
	private EstadoCivilDAO estadoCivilDAO = null;
	private DelegacionDAO delegacionDAO = null;
	private EstatusMiembroDAO estatusDAO = null;
	private OcupacionDAO ocupacionDAO = null;
	private MiembroDAO miembroDAO = null;
	private PadecimientoDAO padecimientoDAO = null;
	private PadecimientosMiembroDAO padecimientoMiembroDAO = null;
	private SubareaDAO subareaDAO = null;
	private MiembroSubareaDAO miembroSubareaDAO = null;
	private BautizoDAO bautizoDAO = null;
	private OtraFeligreciaDAO otraFeligreciaDAO = null;
	private CargoDAO cargoDAO = null;
	private MiembroCargoLlevadoDAO miembroCargoLlevadoDAO = null;
	private MiembroCargoDeseadoDAO miembroCargoDeseadoDAO = null;
	private TemaInteresDAO temaInteresDAO = null;
	private TemaInteresMiembroDAO temaMiembroDAO = null;
	
	public Registro(String xml){
		this.xml = xml;
		familiaDAO = new FamiliaDAO();
		estadoCivilDAO = new EstadoCivilDAO();
		delegacionDAO = new DelegacionDAO();
		estatusDAO = new EstatusMiembroDAO();
		ocupacionDAO = new OcupacionDAO();
		miembroDAO = new MiembroDAO();
		padecimientoDAO = new PadecimientoDAO();
		padecimientoMiembroDAO = new PadecimientosMiembroDAO();
		subareaDAO = new SubareaDAO();
		miembroSubareaDAO = new MiembroSubareaDAO();
		bautizoDAO = new BautizoDAO();
		otraFeligreciaDAO = new OtraFeligreciaDAO();
		cargoDAO = new CargoDAO();
		miembroCargoDeseadoDAO = new MiembroCargoDeseadoDAO();
		miembroCargoLlevadoDAO = new MiembroCargoLlevadoDAO();
		temaInteresDAO = new TemaInteresDAO();
		temaMiembroDAO = new TemaInteresMiembroDAO();
		
		SAXBuilder builder = new SAXBuilder();
		Reader in = new StringReader(xml);
		Document doc = null;
		try{
			doc = builder.build(in);
			root = doc.getRootElement();
		}catch(Exception ex){
			log.error(ex.fillInStackTrace());
		}
	}

	public void guardarRegistro() throws Exception{
		try {
			HibernateSessionFactory.getSession().beginTransaction();
			
			validaFoto();
			Miembro miembro = guardarMiembro();
			savePadecimientos(miembro.getIdMiembro());
			saveSubareas(miembro.getIdMiembro());
			saveBautizo(miembro);
			saveOtrasFeligresias(miembro);
			saveCargosLlevados(miembro);
			saveCargosAgrado(miembro);
			saveTemasInteres(miembro);
			
			HibernateSessionFactory.getSession().getTransaction().commit();
		} catch (Exception e) {
			HibernateSessionFactory.getSession().getTransaction().rollback();
			HibernateSessionFactory.getSession().close();
			throw e;
		}
	}
	
	private String getChildText(String name){
		return getChildText(name, root);
	}
	private String getChildText(String name, Element elem){
		return elem.getChildText(name);
	}
	private Date getChildTextDate(String name) throws Exception{
		if(StringUtils.isEmpty(getChildText(name))){
			return null;
		}else{
			return DateUtils.parseDate(getChildText(name), new String[] {"dd/MM/yyyy"});
		}
	}
	private Integer getlElementInteger(String name){
		if(StringUtils.isEmpty(getChildText(name))){
			return null;
		}else{
			return new Integer(getChildText(name));
		}
	}
	
	private Element getElement(String name){
		return getElement(name, root);
	}
	private Element getElement(String name, Element elem){
		return elem.getChild(name);
	}
	private String getTagUnicoFromXml(String tag, String xmlvar){
		String openTag = "<"+tag+">";
		String closeTag = "</"+tag+">";
		int idx1 = xmlvar.indexOf(openTag);
		if(idx1<=0){
			return null;
		}
		int idx2 = xmlvar.lastIndexOf(closeTag);
		int lengthTag = closeTag.length();
		return xmlvar.substring(idx1, idx2+lengthTag);
	}
	
	private void validaFoto() throws FotoRegistradaException{
		String foto = getChildText("foto");
		if(foto == null){
			return;
		}
		foto = foto.substring(foto.lastIndexOf("/")+1);
		if(!miembroDAO.findByProperty("foto", foto).isEmpty()){
			throw new FotoRegistradaException("La foto ya se encuentra registrada");
		}
	}
	
	private Miembro guardarMiembro() throws Exception{
		Miembro miembro = new Miembro();
		miembro.setNombre(getChildText("nombre"));
		miembro.setApellidoPaterno(getChildText("paterno"));
		miembro.setApellidoMaterno(getChildText("materno"));
		miembro.setFechaDeNacimiento(getChildTextDate("fechaNac"));
		miembro.setSexo(getlElementInteger("sexo").intValue()==1?true:false);
		miembro.setCalleNumero(getChildText("calle"));
		miembro.setTelefonoCasa(getChildText("telCasa"));
		miembro.setTelefonoCelular(getChildText("telCel"));
		miembro.setEmail(getChildText("email"));
		miembro.setEmpresa(getChildText("compania"));
		miembro.setHabilidades(getChildText("habilidades"));
		miembro.setIngresos(getlElementInteger("ingresos"));
		miembro.setIdEstatus(estatusDAO.findById(getlElementInteger("estatus")).getIdEstatus());
		miembro.setMiembroVcDesde(getChildTextDate("asisteDesde"));
		miembro.setEstadoCivil(estadoCivilDAO.findById(getlElementInteger("edoCivil")));
		miembro.setComentario(getChildText("comentario"));
		miembro.setColonia(getChildText("colonia"));
		miembro.setCp(getChildText("cp"));
		miembro.setOcupacion(ocupacionDAO.findById(getlElementInteger("ocupacion")));
		String foto = getChildText("foto");
		foto = foto.substring(foto.lastIndexOf("/")+1);
		miembro.setFoto(foto);
		Familia fam = new Familia();
		fam.setApellido1(getChildText("paterno", getElement("familia")));
		fam.setApellido2(getChildText("materno", getElement("familia")));
		List<Familia> familias = familiaDAO.findByExample(fam);
		if(familias.size() > 0){
			miembro.setFamilia(familias.get(0));
		}
		miembro.setDelegacion(delegacionDAO.findById(getlElementInteger("delegacion")));
		miembro.setSysdate(new Date());
		miembroDAO.save(miembro);
		return miembro;
	}
	
	private void savePadecimientos(Integer idMiembro)
		throws Exception{
		StringTokenizer tokenizer = new StringTokenizer(getChildText("padecimientos"), ",");
		while(tokenizer.hasMoreTokens()){
			String padecimiento = tokenizer.nextToken();
			List<Padecimiento> padecimientosBD = padecimientoDAO.findByProperty("descripcion", padecimiento);
			Padecimiento padecimientoBD;
			if(!padecimientosBD.isEmpty()){
				padecimientoBD = padecimientosBD.get(0);
			}else{
				padecimientoBD = new Padecimiento();
				padecimientoBD.setDescripcion(padecimiento);
				padecimientoDAO.save(padecimientoBD);
			}
			PadecimientosMiembroId id = new PadecimientosMiembroId();
			PadecimientosMiembro padecimientosMiembro = new PadecimientosMiembro();
			id.setIdPadecimiento(padecimientoBD.getIdPadecimiento());
			id.setIdMiembro(idMiembro);
			padecimientosMiembro.setId(id);
			padecimientoMiembroDAO.save(padecimientosMiembro);
		}
	}
	
	private void saveSubareas(Integer idMiembro)
		throws Exception{
		StringTokenizer tokenizer = new StringTokenizer(getChildText("subareas"), ",");
		while(tokenizer.hasMoreTokens()){
			String sub = tokenizer.nextToken();
			Subarea subarea = subareaDAO.findById(new Integer(sub));
			if(subarea != null){
				MiembroSubarea miembroSub = new MiembroSubarea();
				MiembroSubareaId id = new MiembroSubareaId();
				id.setIdSubarea(subarea.getIdSubarea());
				id.setIdMiembro(idMiembro);
				miembroSub.setId(id);
				miembroSubareaDAO.save(miembroSub);
			}
		}
	}
	
	private void saveBautizo(Miembro miembro){
		String bautizoStr = getTagUnicoFromXml("Bautizo", xml);
		Bautizo bautizo = (Bautizo)Parser.xmlToObject(bautizoStr, new Bautizo());
		if(bautizo.getFechaBautizo()!=null){
			bautizo.setMiembro(miembro);
			bautizoDAO.save(bautizo);
		}
	}
	
	private void saveOtrasFeligresias(Miembro miembro)
		throws Exception{
		String feligreciasStr = getTagUnicoFromXml("feligresias",xml);
		List<Object> lstFeligrecias = Parser.xmltoList(feligreciasStr, "OtraFeligrecia", new OtraFeligrecia());
		for (Object obj : lstFeligrecias) {
			OtraFeligrecia otra = (OtraFeligrecia)obj;
			otra.setMiembro(miembro);
			otraFeligreciaDAO.save(otra);
		}
	}
	
	
	private void saveCargosLlevados(Miembro miembro)
	throws Exception{
		String cargosStr = getTagUnicoFromXml("cargosLlevados", xml);
		List<Object> lstCargos = Parser.xmltoList(cargosStr, "MiembroCargoLlevado", new MiembroCargoLlevado());
		for (Object obj : lstCargos) {
			MiembroCargoLlevado miembroCargo = (MiembroCargoLlevado)obj;
			Cargo cargo = miembroCargo.getCargo();
			Cargo cargoBD = getCargoSinId(cargo);
			if(cargoBD==null){
				cargoDAO.save(cargo);
			}else{
				miembroCargo.setCargo(cargoBD);
			}
			miembroCargo.setMiembro(miembro);
			miembroCargoLlevadoDAO.save(miembroCargo);
		}
	}
	
	private void saveCargosAgrado(Miembro miembro)
		throws Exception{
		String cargosStr = getTagUnicoFromXml("cargosAgrado", xml);
		List<Object> lstCargos = Parser.xmltoList(cargosStr, "MiembroCargoDeseado", new MiembroCargoDeseado());
		for (Object obj : lstCargos) {
			MiembroCargoDeseado miembroCargo = (MiembroCargoDeseado)obj;
			Cargo cargo = miembroCargo.getCargo();
			Cargo cargoBD = getCargoSinId(cargo);
			if(cargoBD==null){
				cargoDAO.save(cargo);
			}else{
				miembroCargo.setCargo(cargoBD);
			}
			MiembroCargoDeseadoId id = new MiembroCargoDeseadoId();
			id.setIdCargo(miembroCargo.getCargo().getIdCargo());
			id.setIdMiembro(miembro.getIdMiembro());
			miembroCargo.setId(id);
			miembroCargoDeseadoDAO.save(miembroCargo);
		}
	}
	
	private Cargo getCargoSinId(Cargo cargo){
		List<Cargo> lstCargosBD = cargoDAO.findAll();
		for (Cargo cargoBD : lstCargosBD) {
			if( cargoBD.getDepartamento().getIdDepartamento().compareTo(cargo.getDepartamento().getIdDepartamento())==0
			&& cargoBD.getPosicionCargo().getIdPosicion().compareTo(cargo.getPosicionCargo().getIdPosicion())==0)
				return cargoBD;
			}
		return null;
	}
	
	private void saveTemasInteres(Miembro miembro)
		throws Exception{
		StringTokenizer tokenizer = new StringTokenizer(getChildText("temasInteres"), ",");
		while(tokenizer.hasMoreTokens()){
			String temaId = tokenizer.nextToken();
			TemaInteres tema = temaInteresDAO.findById(new Integer(temaId));
			if(tema != null){
				TemaInteresMiembro temaMiembro = new TemaInteresMiembro();
				TemaInteresMiembroId id = new TemaInteresMiembroId();
				id.setIdMiembro(miembro.getIdMiembro());
				id.setIdTema(tema.getIdTema());
				temaMiembro.setId(id);
				temaMiembroDAO.save(temaMiembro);
			}
		}	
	}

}
